package services

import (
	"time"

	"github.com/deploy-services/v2/log"
)

type daemon_body struct {
	sv      *service
	n       *node
	running bool
	timer   *time.Timer
	e_chan  chan bool
	w_chan  chan bool
}

func (d *daemon_body) start() {
	if d.running {
		return
	}

	if d.e_chan == nil {
		d.e_chan = make(chan bool)
	}
	if d.w_chan == nil {
		d.w_chan = make(chan bool)
	}
	go d.run()
}

func (d *daemon_body) stop() {
	if !d.running {
		return
	}
	d.e_chan <- true
}

func (d *daemon_body) do() error {
	// 1. 先判断是否 health
	// 2. 如果非 health, 那么调用启动函数
	res, err := d.sv.run_cmd_node(d.sv.health_command, d.n)
	if err != nil {
		return err
	}
	health, err := is_health(res)
	if err != nil {
		return err
	}

	if health {
		return nil
	}

	_, err = d.sv.run_cmd_node(d.sv.start_command, d.n)
	return err
}

func (d *daemon_body) run() {
	d.running = true
	defer func() {
		d.running = false
	}()
	d.timer = time.NewTimer(60 * time.Second)
	defer d.timer.Stop()

	running := true
	for running {
		select {
		case <-d.timer.C:
			// 做任务
			err := d.do()
			if err != nil {
				log.Logger().Error("%v Daemon Do Once, Err:%v", d.sv.get_commit_file_key(d.n), err)
			}
			d.timer.Reset(60 * time.Second)
		case <-d.e_chan:
			// 退出任务
			running = false
		}
	}
	log.Logger().Debug("%v Daemon Exit", d.sv.get_commit_file_key(d.n))
}

type daemon_manager struct {
	daemons map[string][]*daemon_body
}

func (d *daemon_manager) register(s *service) {
	if bodys, ok := d.daemons[s.name]; !ok {
		for _, body := range bodys {
			body.stop()
		}
	}

	bodys := []*daemon_body{}
	for _, n := range s.server_nodes {
		body := &daemon_body{
			sv:      s,
			n:       n,
			running: false,
		}
		bodys = append(bodys, body)
	}
	d.daemons[s.name] = bodys
}

func (d *daemon_manager) start(name string) {
	if len(name) == 0 {
		for _, bodys := range d.daemons {
			for _, body := range bodys {
				body.start()
			}
		}
	} else {
		if bodys, ok := d.daemons[name]; ok {
			for _, body := range bodys {
				body.start()
			}
		}
	}
}

func (d *daemon_manager) stop(name string) {
	if len(name) == 0 {
		for _, bodys := range d.daemons {
			for _, body := range bodys {
				body.stop()
			}
		}
	} else {
		if bodys, ok := d.daemons[name]; ok {
			for _, body := range bodys {
				body.stop()
			}
		}
	}
}

func (d *daemon_manager) status(name string) (names []string, n_names []string, hosts []string, bases []string, stats []bool) {
	if len(name) == 0 {
		for _, bodys := range d.daemons {
			for _, body := range bodys {
				names = append(names, body.sv.name)
				n_names = append(n_names, body.n.name)
				hosts = append(hosts, body.n.host)
				bases = append(bases, body.n.base)
				stats = append(stats, body.running)
			}
		}
	} else {
		if bodys, ok := d.daemons[name]; ok {
			for _, body := range bodys {
				names = append(names, body.sv.name)
				n_names = append(n_names, body.n.name)
				hosts = append(hosts, body.n.host)
				bases = append(bases, body.n.base)
				stats = append(stats, body.running)
			}
		}
	}

	return names, n_names, hosts, bases, stats
}

func newDaemonManager() *daemon_manager {
	return &daemon_manager{
		daemons: make(map[string][]*daemon_body),
	}
}

var global_daemon_manager *daemon_manager

func init() {
	global_daemon_manager = newDaemonManager()
}
